package org.ithasu.uBroadcast;

import java.io.PrintStream;
import java.util.Arrays;

public final class UMessage {

	public final static int UB_MESSAGE_SIZE = 255 + 3;
	protected byte buffer[];

	public UMessage() {
		clear();
	}

	public UMessage(byte data[]) {
		this.buffer = data;
	}

	// --- Properties ----------------------------------------

	public byte getType() {
		return buffer[0];
	}

	public void setType(byte type) {
		buffer[0] = type;
	}

	public byte getSize() {
		return buffer[1];
	}

	public byte getChecksum() {
		return buffer[getPtr()];
	}

	/** @return Position of checksum, also the position to write next data */
	private int getPtr() {
		return getSize() + 2;
	}

	// --- Utils ----------------------------------------

	public void clear() {
		buffer = new byte[UB_MESSAGE_SIZE];
		Arrays.fill(buffer, (byte) 0x00);
	}

	public boolean isValid() {
		byte check = 0x00;
		for (int i = 2; i < getPtr(); i++) {
			check ^= buffer[i];
		}
		return check == getChecksum();
	}

	public byte[] toByteArray() {
		return Arrays.copyOfRange(buffer, 0, getPtr() + 2);
	}

	public void copy(UMessage msg) {
		this.buffer = Arrays.copyOf(msg.buffer, msg.buffer.length);
	}

	@Override
	public boolean equals(Object obj) {
		return obj instanceof UMessage
				&& Arrays.equals(((UMessage) obj).buffer, this.buffer);
	}

	// --- Add data ----------------------------------------

	public boolean add(byte b) {
		int ptr = getPtr();
		if (ptr + 1 >= UB_MESSAGE_SIZE) {
			return false;
		}
		// --- Read previous checksum ---
		byte checksum = buffer[ptr];
		// --- Write data ---
		buffer[ptr++] = b;
		checksum ^= b; // Update checksum
		buffer[1]++; // Increment size
		// --- Write new checksum ---
		buffer[ptr] = checksum;
		return true;
	}

	public boolean add(String s) {
		int ptr = getPtr();
		byte data[] = s.getBytes();
		if (ptr + data.length + 1 >= UB_MESSAGE_SIZE) {
			return false;
		}
		// --- Read previous checksum ---
		byte checksum = buffer[ptr];

		// --- Write data ---
		for (byte b : data) {
			buffer[ptr++] = b;
			checksum ^= b; // Update checksum
			buffer[1]++; // Increment size
		}
		// --- Write new checksum ---
		buffer[ptr] = checksum;
		return true;
	}

	// --- Debug ----------------------------------------

	public void debug(PrintStream out) {
		out.println("---- ---- ---- ---- ---- ---- ---- ----");
		for (int i = 0; i <= getPtr(); i++) {
			if (i != 0 && i % 8 == 0) {
				out.print('\n');
			}
			String hex = Integer.toHexString(buffer[i] & 0x00ff);
			while (hex.length() < 2) {
				hex += "0";
			}
			out.print("0x" + hex + " ");
		}
		out.print('\n');
	}
}
